// Copyright 2013 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.api.ads.dfa.matchtables;

import com.google.api.ads.dfa.axis.factory.DfaServices;
import com.google.api.ads.dfa.axis.v1_20.ApiException;
import com.google.api.ads.dfa.axis.v1_20.Campaign;
import com.google.api.ads.dfa.axis.v1_20.CampaignRecordSet;
import com.google.api.ads.dfa.axis.v1_20.CampaignRemote;
import com.google.api.ads.dfa.axis.v1_20.CampaignSearchCriteria;
import com.google.api.ads.dfa.lib.client.DfaSession;

import java.rmi.RemoteException;
import java.text.SimpleDateFormat;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * Implementation of LookupObject that will generate Campaign match tables. Extends
 * AbstractSimpleLookupObject to handle aggregation of Campaign/Buy IDs.
 * 
 * @author Moshe Kahan
 */
public class CampaignLookup implements LookupObject {

  private final CampaignRemote campaignService;
  private TableSettings tableSettings;
  private int campaignColumnIndex;
  private int orderIdColumnIndex;
  private Set<Long> campaignIds;

  /**
   * Constructor accepts DFA service/session objects needed to create SOAP remotes to the
   * API.
   *
   * @param dfaServices DFA services object needed to create SOAP remotes to the API
   * @param session DFA session object needed to create SOAP remotes to the API
   * @param tableSettings match table application configuration used as a MatchTable object factory
   */
  CampaignLookup(DfaServices dfaServices, DfaSession session, TableSettings tableSettings) {
    // Request the campaign service from the service client factory.
    this(dfaServices.get(session, CampaignRemote.class), tableSettings);
  }

  CampaignLookup(CampaignRemote campaignService, TableSettings tableSettings) {
    this.campaignService = campaignService;
    this.tableSettings = tableSettings;
    campaignColumnIndex = -1;
    orderIdColumnIndex = -1;
    campaignIds = new HashSet<Long>();
  }

  /**
   * Called to parse the DT header row.
   *
   * @param index in DT file columns
   * @param header name of this DT file field/column
   */
  public void addHeader(int index, String header) throws DataTransferFileException {
    if (LookupField.BuyId.getFieldName().equals(header)) {
      campaignColumnIndex = index;
    } else if (LookupField.OrderId.getFieldName().equals(header)) {
      orderIdColumnIndex = index;
    }
  }

  /**
   * Called to clear the DT header information' usually because you're processing a new file.
   */
  public void clearHeaders() {
    campaignColumnIndex = -1;
    orderIdColumnIndex = -1;
  }

  /**
   * Called to parse the DT row.
   *
   * @param values array of tokenized Strings of DT file line
   */
  public void addValues(String[] values) throws DataTransferFileException {
    if (campaignColumnIndex > -1) {
      String campaignId = values[campaignColumnIndex];
      if (campaignId != null &&  !campaignId.isEmpty() && !campaignId.equals("0")) {
        campaignIds.add(Long.valueOf(campaignId));
      } else if (orderIdColumnIndex > -1) {
        campaignId = values[orderIdColumnIndex];
        if (campaignId != null &&  !campaignId.isEmpty() && !campaignId.equals("0")) {
          campaignIds.add(Long.valueOf(campaignId));
        }
      }
    }
  }

  /**
   * Called when parsing/aggregation is complete and match table generation should commence.
   *
   * @param outputPath location of match table to be generated.
   */
  public void generateMatchTable(String outputPath)
      throws MatchTableFileException, DfaRemoteException {
    MatchTable campaignMatchTable = tableSettings.createMatchTable(MatchTable.Type.CAMPAIGN);
    if (campaignMatchTable != null) {
      campaignMatchTable.open(outputPath);
      generateCampaignMatchTable(campaignIds, campaignMatchTable);
      campaignMatchTable.close();
    }
  }

  // Generates all campaign lookups and match table rows for all Buy-IDs.
  private void generateCampaignMatchTable(Set<Long> campaignIds, MatchTable campaignMatchTable)
      throws DfaRemoteException {

    Progress.printProgress(campaignMatchTable);
    SoapPageableLookup<Campaign, CampaignSearchCriteria> soapLookup =
        new SoapPageableLookup<Campaign, CampaignSearchCriteria>(campaignIds,
            new CampaignSoapLookupCallback());

    SimpleDateFormat dateFormat = new SimpleDateFormat("MM-dd-yyyy");
    while (soapLookup.hasNext()) {
      Campaign result = soapLookup.next();
      if (campaignMatchTable != null) {
        campaignMatchTable.write(
            Long.toString(result.getAdvertiserId()),
            Long.toString(result.getId()),
            result.getName(),
            dateFormat.format(result.getStartDate().getTime()),
            dateFormat.format(result.getEndDate().getTime()),
            "1",
            result.getBillingInvoiceNotation());
      }
    }
  }

  private class CampaignSoapLookupCallback implements
    SoapPageableLookupCallback<Campaign, CampaignSearchCriteria> {

    public int getRecords(CampaignSearchCriteria criteria, List<Campaign> recordList)
        throws ApiException, RemoteException {
      CampaignRecordSet records = campaignService.getCampaignsByCriteria(criteria);
      int pages = records.getTotalNumberOfPages();
      for (Campaign record : records.getRecords()) {
        recordList.add(record);
      }
      return pages;
    }

    public CampaignSearchCriteria getCriteria(long[] ids) {
      CampaignSearchCriteria searchCriteria = new CampaignSearchCriteria();
      if (ids != null) {
        searchCriteria.setIds(ids);
      }
      return searchCriteria;
    }
  }
}
